﻿using System;
using System.Linq;
using System.Text;
using NUnit.Framework;
using SharpSvn;
using System.IO;
using SvnFlow;
using System.Collections.Generic;

namespace SvnFlowTests
{
    [TestFixture]
    public class FlowSvnClientTest
    {
        private readonly string[] m_Work1Files = new[] { "text1.txt", "text2.txt", "text4.txt" };
        private readonly string[] m_Work2Files = new[] { "text-1.txt", "text-2.txt", "text-3.txt" };

        [Test]
        public void LoadFromDumpTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep1DumpName);

            var client = new SvnClient();
            var sb = new StringBuilder();

            // ReSharper disable AccessToModifiedClosure
            client.Log(new Uri(TestHelper.m_repo1Path), (o, e) => sb
               .Append(e.Author).Append("|")
               .Append(e.Time.ToString(SvnHelper.TimeFormat)).Append("|")
               .Append(e.Revision).Append("|")
               .Append(e.LogMessage).Append("\r\n"));
            // ReSharper restore AccessToModifiedClosure
            Assert.That(sb.ToString(), Is.EqualTo(TestHelper.RepoLog1));

            TestHelper.DeleteRepository(TestHelper.m_repo1Path);

            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);

            sb = new StringBuilder();

            client.Log(new Uri(TestHelper.m_repo2Path), (o, e) => sb
               .Append(e.Author).Append("|")
               .Append(e.Time.ToString(SvnHelper.TimeFormat)).Append("|")
               .Append(e.Revision).Append("|")
               .Append(e.LogMessage).Append("\r\n"));

            Assert.That(sb.ToString(), Is.EqualTo(TestHelper.RepoLog2));

            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void CreateWorkingCopyTest()
        {
            var flowClient = new FlowSvnClient(new SvnClient());

            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep1DumpName);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);

            var helper = new TestHelper();

            flowClient.PrepareWorkingCopy(helper.branchFrom);

            var files = Directory.GetFiles(TestHelper.m_work1Path).Select(x => Path.GetFileName(x)).ToArray();
            Assert.That(files, Is.EquivalentTo(m_Work1Files));

            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);

            flowClient.PrepareWorkingCopy(helper.branchTo);

            files = Directory.GetFiles(TestHelper.m_work2Path).Select(x => Path.GetFileName(x)).ToArray();
            Assert.That(files, Is.EquivalentTo(m_Work2Files));


            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }


        [Test]
        public void CreateWorkingCopyTest2()
        {
            var svnClient = new SvnClient();
            var flowClient = new FlowSvnClient(svnClient);
            var helper = new TestHelper();

            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);
            if (Directory.Exists(TestHelper.m_work2Path))
                SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);

            flowClient.PrepareWorkingCopy(helper.branchTo);

            // create new file
            var newFileName = Path.Combine(TestHelper.m_work2Path, "newfile.txt");
            using (File.Create(newFileName))
            {
            }
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Not.Empty);
            flowClient.PrepareWorkingCopy(helper.branchTo);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Empty);

            // delete exists file
            var deleteFileName = Path.Combine(TestHelper.m_work2Path, "text-1.txt");
            File.Delete(deleteFileName);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Not.Empty);
            flowClient.PrepareWorkingCopy(helper.branchTo);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Empty);

            // modify exists file
            TestHelper.EditFile(Path.Combine(TestHelper.m_work2Path, "text-1.txt"),
                     "forgetting", "rooftree");
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Not.Empty);
            flowClient.PrepareWorkingCopy(helper.branchTo);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Empty);

            // create new folder
            var createdDirectory = Path.Combine(TestHelper.m_work2Path, "NewFolder");
            Directory.CreateDirectory(createdDirectory);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Not.Empty);
            flowClient.PrepareWorkingCopy(helper.branchTo);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Empty);

            // modify property
            var propertyFileName = Path.Combine(TestHelper.m_work2Path, "text-2.txt");
            svnClient.SetProperty(propertyFileName, "testproperty", "value1 for test");
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Not.Empty);
            flowClient.PrepareWorkingCopy(helper.branchTo);
            Assert.That(GetFolderChanges(TestHelper.m_work2Path), Is.Empty);

            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
        }


        [Test]
        public void MergeSimpleTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep1DumpName);
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            flowClient.PrepareWorkingCopy(helper.branchFrom);
            flowClient.PrepareWorkingCopy(helper.branchTo);

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo, string.Empty,
                    new SvnRevisionRange(0, flowClient.GetWorkingCopyRevision(helper.branchFrom)));

            var files = Directory.GetFiles(TestHelper.m_work2Path).Select(x => Path.GetFileName(x)).ToArray();
            Assert.That(files, Is.EquivalentTo(m_Work1Files.Union(m_Work2Files)));

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void MergeWithTreeConflictTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep1DumpName);
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            var sourceFileName = Path.Combine(helper.branchTo.FullPath, "text-1.txt");
            var destFileName = Path.Combine(helper.branchFrom.FullPath, "text-1.txt");
            File.Copy(sourceFileName, destFileName);

            TestHelper.EditFile(destFileName, "And Gall's", "String 1 asdf");
            client.Add(destFileName);
            CommitAndUpdate(helper.branchFrom, "Conflict From");

            var mergeConflict = flowClient.MergeChanges(
                helper.branchFrom, string.Empty, helper.branchTo, string.Empty, helper.branchFrom.Range);
            Assert.That(mergeConflict, Is.EquivalentTo(
                new[]
                    {
                        new TreeConflict(Path.Combine(helper.branchTo.FullPath, "text-1.txt"))
                    }));

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void MergeWithMergeConflictTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep2DumpName);
            TestHelper.CreateEmptyRepository(TestHelper.m_repo2Path);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo, 
                string.Empty, helper.branchFrom.Range);
            CommitAndUpdate(helper.branchTo, "Prepare Repository");

            TestHelper.EditFile(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"), "And Gall's", "String 1 asdf");
            TestHelper.EditFile(Path.Combine(helper.branchFrom.FullPath, "text-2.txt"), "Pretty Brick Story", "Carnegie Mellon University");
            CommitAndUpdate(helper.branchFrom, "Conflict From");

            TestHelper.EditFile(Path.Combine(helper.branchTo.FullPath, "text-1.txt"), "And Gall's", "Pretty Brick Story");
            TestHelper.EditFile(Path.Combine(helper.branchTo.FullPath, "text-2.txt"), "Pretty Brick Story", "String 1 asdf");
            CommitAndUpdate(helper.branchTo, "Conflict To");

            var mergeConflict = flowClient.MergeChanges(helper.branchFrom, string.Empty, 
                helper.branchTo, string.Empty, helper.branchFrom.Range);
            Assert.That(mergeConflict, Is.EquivalentTo(
                new MergeConflict[]
                    {
                        new EditConflict(Path.Combine(helper.branchTo.FullPath, "text-1.txt")),
                        new EditConflict(Path.Combine(helper.branchTo.FullPath, "text-2.txt"))
                    }
                ));

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void BuildLogMessageTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep1DumpName);
            var branchInfo = new BranchInfo(new Uri(TestHelper.m_repo1Path), "from", TestHelper.m_work1Path, new SvnRevisionRange(0,0)) { WorkingCopyRevision = 0 };
            var flowClient = new FlowSvnClient(new SvnClient());
            var log = flowClient.BuildLogMessage(branchInfo, new SvnRevisionRange(SvnRevision.Zero, SvnRevision.Head), string.Empty);
            Assert.That(log, Is.EqualTo(
                new List<SvnLogMessage> {
                    new SvnLogMessage { Revision = 0, Author = null, Time = DateTime.Parse("2010.11.08 19:27:05.9078010"), Message = null },
                    new SvnLogMessage { Revision = 1, Author = "User1", Time = DateTime.Parse("2010.11.08 19:29:00.9131710"), Message = string.Empty },
                    new SvnLogMessage { Revision = 2, Author = "User1", Time = DateTime.Parse("2010.11.08 19:34:42.9750320"), Message = "First Commit from User1" }
                }));
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
        }

        [Test]
        public void MarkPropertyConflictsResolvedTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep2DumpName);
            TestHelper.CreateEmptyRepository(TestHelper.m_repo2Path);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo, 
                string.Empty, helper.branchFrom.Range);
            CommitAndUpdate(helper.branchTo, "prepare repository");

            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"),
                "testproperty", "value1 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchTo.FullPath, "text-1.txt"),
                "testproperty", "value2 for test"), Is.True);
            CommitAndUpdate(helper.branchFrom, "property test");
            CommitAndUpdate(helper.branchTo, "property test");

            var status = new List<SvnStatusEventArgs>();
            var checkFileName = Path.Combine(helper.branchTo.FullPath, "text-1.txt");
            var conflicts = flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo,
                string.Empty, helper.branchFrom.Range);
            Assert.That(conflicts, Is.EquivalentTo(new[] { new EditConflict(checkFileName) }));
            // ReSharper disable AccessToModifiedClosure
            client.Status(checkFileName, (o, e) => status.Add(e));
            // ReSharper restore AccessToModifiedClosure
            Assert.That(status[0].LocalPropertyStatus, Is.EqualTo(SvnStatus.Conflicted));

            flowClient.MarkPropertyConflictsResolved(helper.branchTo, string.Empty);
            status = new List<SvnStatusEventArgs>();
            client.Status(checkFileName, (o, e) => status.Add(e));
            Assert.That(status, Is.Empty);

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void MarkPropertyConflictsResolvedTest2()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep2DumpName);
            TestHelper.CreateEmptyRepository(TestHelper.m_repo2Path);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo, string.Empty,
                helper.branchFrom.Range);
            CommitAndUpdate(helper.branchTo, "prepare repository");

            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"),
                "testproperty", "value1 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchTo.FullPath, "text-1.txt"),
                "testproperty", "value2 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "SubFolder/text-4.txt"),
                "testproperty", "value1 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchTo.FullPath, "SubFolder/text-4.txt"),
                "testproperty", "value2 for test"), Is.True);
            CommitAndUpdate(helper.branchFrom, "property test");
            CommitAndUpdate(helper.branchTo, "property test");

            var status = new List<string>();
            var checkFileName1 = Path.Combine(helper.branchTo.FullPath, "text-1.txt");
            var checkFileName2 = Path.Combine(helper.branchTo.FullPath, @"SubFolder\text-4.txt");
            var conflicts = flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo,
                string.Empty, helper.branchFrom.Range);
            Assert.That(conflicts, Is.EquivalentTo(new[] { new EditConflict(checkFileName1), new EditConflict(checkFileName2) }));
            // ReSharper disable AccessToModifiedClosure
            client.Status(helper.branchTo.FullPath, (o, e) =>
                                                 {
                                                     if (e.LocalPropertyStatus == SvnStatus.Conflicted)
                                                         status.Add(Path.GetFileName(e.Path));
                                                 });
            // ReSharper restore AccessToModifiedClosure
            Assert.That(status, Is.EquivalentTo(new List<string> { "text-1.txt", "text-4.txt" }));

            flowClient.MarkPropertyConflictsResolved(helper.branchTo, "SubFolder");
            status = new List<string>();
            client.Status(helper.branchTo.FullPath, (o, e) =>
            {
                if (e.LocalPropertyStatus == SvnStatus.Conflicted)
                    status.Add(Path.GetFileName(e.Path));
            });
            Assert.That(status, Is.EquivalentTo(new List<string> { "text-1.txt" }));

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void FixSpecialPropertiesTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep2DumpName);
            TestHelper.CreateEmptyRepository(TestHelper.m_repo2Path);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"),
                    "testproperty", "value1 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-2.txt"),
                    "svn:keywords", "value1 for test"), Is.True);
            CommitAndUpdate(helper.branchFrom, "commit properties");

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo, string.Empty,
                new SvnRevisionRange(0, helper.branchFrom.WorkingCopyRevision.Value));
            CommitAndUpdate(helper.branchTo, "prepare repository");

            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"),
                    "testproperty", "value2 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-2.txt"),
                    "svn:keywords", "value2 for test"), Is.True);
            CommitAndUpdate(helper.branchFrom, "commit properties");

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo,
                string.Empty, helper.branchFrom.Range);
            flowClient.FixSpecialProperties(
                helper.branchTo, string.Empty, BranchesFile.DefaultPropertiesAllowedToMerge.Split(new[] { ',' }));

            string value;
            client.GetProperty(Path.Combine(helper.branchTo.FullPath, "text-1.txt"), "testproperty", out value);
            Assert.That(value, Is.EqualTo("value1 for test"));
            client.GetProperty(Path.Combine(helper.branchTo.FullPath, "text-2.txt"), "svn:keywords", out value);
            Assert.That(value, Is.EqualTo("value2 for test"));

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void FixSpecialPropertiesTest2()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep2DumpName);
            TestHelper.CreateEmptyRepository(TestHelper.m_repo2Path);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"),
                    "testproperty", "value1 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "SubFolder/text-4.txt"),
                    "testproperty", "value1 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "SubFolder/text-5.txt"),
                    "svn:keywords", "value1 for test"), Is.True);
            CommitAndUpdate(helper.branchFrom, "commit properties");

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo, string.Empty,
                new SvnRevisionRange(0, helper.branchFrom.WorkingCopyRevision.Value));
            CommitAndUpdate(helper.branchTo, "prepare repository");

            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "text-1.txt"),
                    "testproperty", "value2 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "SubFolder/text-4.txt"),
                    "testproperty", "value2 for test"), Is.True);
            Assert.That(client.SetProperty(Path.Combine(helper.branchFrom.FullPath, "SubFolder/text-5.txt"),
                    "svn:keywords", "value2 for test"), Is.True);
            CommitAndUpdate(helper.branchFrom, "commit properties");

            flowClient.MergeChanges(helper.branchFrom, string.Empty, helper.branchTo,
                string.Empty, helper.branchFrom.Range);
            flowClient.FixSpecialProperties(helper.branchTo, "SubFolder", 
                BranchesFile.DefaultPropertiesAllowedToMerge.Split(new[] { ',' }));

            string value;
            client.GetProperty(Path.Combine(helper.branchTo.FullPath, "text-1.txt"), "testproperty", out value);
            Assert.That(value, Is.EqualTo("value2 for test"));
            client.GetProperty(Path.Combine(helper.branchTo.FullPath, "SubFolder/text-4.txt"), "testproperty", out value);
            Assert.That(value, Is.EqualTo("value1 for test"));
            client.GetProperty(Path.Combine(helper.branchTo.FullPath, "SubFolder/text-5.txt"), "svn:keywords", out value);
            Assert.That(value, Is.EqualTo("value2 for test"));

            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void CollectSubfolderLogMessageTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);
            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            var logMessages = flowClient.BuildLogMessage(helper.branchTo,
                new SvnRevisionRange(SvnRevision.Zero, SvnRevision.Head), string.Empty);
            Assert.That(logMessages.Count, Is.EqualTo(3));
            logMessages = flowClient.BuildLogMessage(helper.branchTo,
                new SvnRevisionRange(SvnRevision.Zero, SvnRevision.Head), "SubFolder");
            Assert.That(logMessages, Is.EquivalentTo(new List<SvnLogMessage>
                                     {
                                         new SvnLogMessage
                                             {
                                                 Revision = 1,
                                                 Author = "User1",
                                                 Time = DateTime.Parse("2010.11.08 19:29:09.8560300"),
                                                 Message = String.Empty
                                             },
                                         new SvnLogMessage
                                             {
                                                 Revision = 2,
                                                 Author = "User1",
                                                 Time = DateTime.Parse("2010.11.08 20:23:27.3901340"),
                                                 Message = "Second Commit from User1"
                                             }
                                     }));

            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
        }

        [Test]
        public void MergeSubfoldersTest()
        {
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo1Path, TestHelper.Rep1DumpName);
            TestHelper.ReCreateRepositoryFromDump(TestHelper.m_repo2Path, TestHelper.Rep2DumpName);

            var client = new SvnClient();
            var flowClient = new FlowSvnClient(client);
            var helper = new TestHelper();

            if (Directory.Exists(helper.branchFrom.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchFrom.FullPath);
            if (Directory.Exists(helper.branchTo.FullPath))
                SvnHelper.DeleteRecursiveFolder(helper.branchTo.FullPath);

            flowClient.PrepareWorkingCopy(helper.branchTo);
            helper.branchTo.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchTo);
            flowClient.PrepareWorkingCopy(helper.branchFrom);
            helper.branchFrom.WorkingCopyRevision = flowClient.GetWorkingCopyRevision(helper.branchFrom);

            flowClient.MergeChanges(helper.branchTo, "SubFolder", helper.branchFrom, 
                "DiffSub", helper.branchTo.Range);

            var changes = GetFolderChanges(TestHelper.m_work1Path);
            changes.ForEach(Console.WriteLine);
            Assert.That(changes.Count, Is.EqualTo(1));

            TestHelper.DeleteRepository(TestHelper.m_repo1Path);
            TestHelper.DeleteRepository(TestHelper.m_repo2Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work1Path);
            SvnHelper.DeleteRecursiveFolder(TestHelper.m_work2Path);
        }

        #region Helper Functions

        public void CommitAndUpdate(BranchInfo branch, string logMessage)
        {
            var svn = new SvnClient();

            Logger.WriteLine("Commit branch {0}", branch.FullPath);

            SvnCommitResult commitResult;
            svn.Commit(branch.FullPath,
                new SvnCommitArgs { Depth = SvnDepth.Infinity, LogMessage = logMessage },
                out commitResult);

            SvnUpdateResult updateResult;
            svn.Update(branch.FullPath, new SvnUpdateArgs(), out updateResult);

            SvnInfoEventArgs infoEventArgs;
            svn.GetInfo(new SvnPathTarget(branch.FullPath), out infoEventArgs);

            branch.UpdateRevisions();
            branch.WorkingCopyRevision = infoEventArgs.Revision;
        }

        private static List<string> GetFolderChanges(string workPath)
        {
            var sl = new List<string>();
            new SvnClient().Status(
                workPath,
                new SvnStatusArgs { RetrieveRemoteStatus = true },
                (o, args) => sl.Add(args.LocalContentStatus + " " + args.LocalPropertyStatus + " " + args.Path));
            return sl;
        }

        #endregion
    }
}
